1
2
3
4
5
6 package spoon.reflect.visitor;
7
8 import spoon.processing.AbstractProcessor;
9 import spoon.processing.Processor;
10 import spoon.reflect.code.CtConstructorCall;
11 import spoon.reflect.code.CtTargetedExpression;
12 import spoon.reflect.declaration.CtCompilationUnit;
13 import spoon.reflect.declaration.CtElement;
14 import spoon.reflect.declaration.CtPackage;
15 import spoon.reflect.path.CtRole;
16 import spoon.reflect.reference.CtExecutableReference;
17 import spoon.reflect.reference.CtFieldReference;
18 import spoon.reflect.reference.CtTypeReference;
19 import spoon.reflect.reference.CtVariableReference;
20 import spoon.reflect.visitor.chain.CtScannerListener;
21 import spoon.reflect.visitor.chain.ScanningMode;
22 import spoon.support.Experimental;
23
24 import java.util.Arrays;
25 import java.util.HashSet;
26 import java.util.Set;
27
28
29
30
31
32
33
34
35 @Experimental
36 abstract class ImportAnalyzer<U> extends AbstractProcessor<CtElement> {
37
38 protected EarlyTerminatingScanner scanner;
39 @Override
40 public void process(CtElement el) {
41 scanner = createScanner();
42 CtScannerListener listener = createScannerListener();
43 scanner.setListener(listener);
44 if (el instanceof CtCompilationUnit) {
45 process(scanner, (CtCompilationUnit) el);
46 } else {
47 scanner.scan(el);
48 }
49 }
50
51 protected static void process(CtScanner scanner, CtCompilationUnit cu) {
52 scanner.enter(cu);
53 switch (cu.getUnitType()) {
54 case MODULE_DECLARATION:
55 case UNKNOWN:
56 break;
57 case PACKAGE_DECLARATION:
58
59
60 CtPackage pack = cu.getDeclaredPackage();
61 scanner.scan(pack.getAnnotations());
62 break;
63 case TYPE_DECLARATION:
64 for (CtTypeReference<?> typeRef : cu.getDeclaredTypeReferences()) {
65 scanner.scan(typeRef.getTypeDeclaration());
66 }
67 break;
68 }
69 scanner.exit(cu);
70 }
71
72 protected CtScannerListener createScannerListener() {
73 return new ScannerListener();
74 }
75
76
77 protected static Set<CtRole> IGNORED_ROLES_WHEN_IMPLICIT = new HashSet<>(Arrays.asList(
78
79 CtRole.TYPE_ARGUMENT,
80
81 CtRole.BOUNDING_TYPE,
82
83 CtRole.TYPE
84 ));
85
86
87
88
89
90 protected class ScannerListener implements CtScannerListener {
91 protected Set<CtRole> ignoredRoles = IGNORED_ROLES_WHEN_IMPLICIT;
92
93 ScannerListener() {
94 super();
95 }
96
97 @Override
98 public ScanningMode enter(CtRole role, CtElement element) {
99 if (element == null) {
100 return ScanningMode.SKIP_ALL;
101 }
102 if (role == CtRole.VARIABLE && element instanceof CtVariableReference) {
103
104 return ScanningMode.SKIP_ALL;
105 }
106 if (element.isParentInitialized()) {
107 CtElement parent = element.getParent();
108 if (role == CtRole.DECLARING_TYPE && element instanceof CtTypeReference) {
109 if (parent instanceof CtFieldReference) {
110
111 return ScanningMode.SKIP_ALL;
112 }
113 if (parent instanceof CtExecutableReference) {
114
115
116
117
118
119 return ScanningMode.SKIP_ALL;
120 } else if (parent instanceof CtTypeReference) {
121
122
123
124
125
126
127
128
129
130
131
132
133
134 if (!((CtTypeReference) parent).getAccessType().equals(element)) {
135 return ScanningMode.SKIP_ALL;
136 }
137 }
138 }
139 if (role == CtRole.TYPE && element instanceof CtTypeReference) {
140 if (parent instanceof CtFieldReference) {
141
142 return ScanningMode.SKIP_ALL;
143 }
144 if (parent instanceof CtExecutableReference) {
145 CtElement parent2 = null;
146 if (parent.isParentInitialized()) {
147 parent2 = parent.getParent();
148 }
149 if (parent2 instanceof CtConstructorCall<?>) {
150
151
152 } else {
153
154
155
156
157
158 return ScanningMode.SKIP_ALL;
159 }
160 }
161
162
163
164
165
166 }
167 if (role == CtRole.ARGUMENT_TYPE) {
168
169
170
171
172 return ScanningMode.SKIP_ALL;
173 }
174 }
175 if (element.isImplicit() && ignoredRoles.contains(role)) {
176
177 return ScanningMode.SKIP_ALL;
178 }
179 onEnter(getScannerContextInformation(), role, element);
180 return ScanningMode.NORMAL;
181 }
182 }
183
184
185 protected void onEnter(U context, CtRole role, CtElement element) {
186
187 if (element instanceof CtTargetedExpression) {
188 CtTargetedExpression<?, ?> targetedExpression = (CtTargetedExpression<?, ?>) element;
189 handleTargetedExpression(targetedExpression, context);
190 } else if (element instanceof CtTypeReference<?>) {
191
192 element.accept(new CtAbstractVisitor() {
193 @Override
194 public <T> void visitCtTypeReference(CtTypeReference<T> reference) {
195 handleTypeReference((CtTypeReference<?>) element, context, role);
196 }
197 });
198 }
199 }
200
201
202 protected abstract U getScannerContextInformation();
203
204
205 protected abstract EarlyTerminatingScanner createScanner();
206
207
208 protected abstract void handleTypeReference(CtTypeReference<?> element, U context, CtRole role);
209
210
211 protected abstract void handleTargetedExpression(CtTargetedExpression<?, ?> targetedExpression, U context);
212
213
214
215
216 protected static <T extends CtElement> T getParentIfType(CtElement element, Class<T> type) {
217 if (element == null || !element.isParentInitialized()) {
218 return null;
219 }
220 CtElement parent = element.getParent();
221 if (type.isInstance(parent)) {
222 return type.cast(parent);
223 }
224 return null;
225 }
226 }